﻿using System;
using System.Reflection;
using Shell.PocoDot;

namespace Shell.DomainDot
{
    public class WithAllInjector : DomainInjector
    {
        private static Type typeSupported;
        private IDataContextFactory pocoFactory;

        static WithAllInjector()
        {
            typeSupported = typeof(WithAll<>);
        }

        public WithAllInjector()
        {
            var seeker = ObjectSeeker.Seeker;
            this.pocoFactory = seeker.Seek<IDataContextFactory>();
        }

        protected override Type TargetDomainType
        {
            get { return typeSupported; }
        }

        protected override object CreateDomainDot<TDomainDot>(TDomainDot dot, PropertyInfo domainSegment)
        {
            var c = domainSegment.PropertyType.GetConstructors()[0];

            var repository = this.MakePocoRepository(domainSegment);
            if (repository == null)
            {
                throw new InvalidOperationException("Could not make respository for the specified domain dot.");
            }

            return c.Invoke(new object[] { repository });
        }

        protected virtual IPersistent MakePocoRepository(PropertyInfo domainSegment)
        {
            var pocoArgument = this.GetPocoType(domainSegment);
            if (pocoArgument == null)
            {
                //TODO
            }
            var factoryType = this.pocoFactory.GetType();
            var createMethod = factoryType.GetMethod("Create");
            var m = createMethod.MakeGenericMethod(pocoArgument);
            var repository = m.Invoke(this.pocoFactory, new object[] { });
            return repository == null ? null : repository as IPersistent;
        }

        protected virtual Type GetPocoType(PropertyInfo domainSegment)
        {
            var t = domainSegment.PropertyType;
            if (t.IsGenericType && t.GetGenericTypeDefinition() == this.TargetDomainType)
            {
                return t.GetGenericArguments()[0];
            }
            return null;
        }

        protected override void OnDispose(bool disposing)
        {
            if (disposing)
            {
                this.pocoFactory = null;
            }
        }
    }
}
